// Class for characters with animations
//
// Nick Kitten
// 2009

#include "Agent.h"

using namespace std;


Agent::Agent( char * fileName, int id, Pathfinder & pather, Grid<char> & occGrid, float walkSpeed, float turnSpeed ) 
: TexturedObj( fileName, id ), pathfinder( pather ), changedState( false ), occGrid( occGrid )
{
	//Animation animations[ maxAnimations ];
	speed = 0;
	setState( Idle );
	currPath = list<Triple>();
	traverser = PathTraverser( & currPath, walkSpeed, turnSpeed );
}

Agent::~Agent()
{
}

void Agent::addAnimation( Animation::Action action, char * fileName, int speed, 
						 bool loopable, bool velocityDependent )
{
	Animation newAnim;
	newAnim.startFrame = dbTotalObjectFrames( this->getID() ) + 1;
	dbAppendObject( fileName, this->getID(), newAnim.startFrame );
	newAnim.duration = dbTotalObjectFrames( this->getID() ) - newAnim.startFrame;
	newAnim.speed = speed;
	newAnim.loopable = loopable;
	newAnim.velocDependent = velocityDependent;
	this->animations[action] = newAnim;
}

void Agent::playAnimation( Animation::Action action )
{
	const Animation & anim = this->animations[action];
	int id = this->getID();
	//this->stopAnimation();
	dbSetObjectFrame( id, anim.startFrame );

	// need to also check for velocity-dependent speed later on
	dbSetObjectSpeed( id, anim.speed );

	if( anim.loopable )
	{
		dbLoopObject( id, anim.startFrame, anim.startFrame + anim.duration );
	}
	else
	{
		dbPlayObject( id, anim.startFrame, anim.startFrame + anim.duration );
	}
}

void Agent::stopAnimation()
{
	dbStopObject( this->getID() );
}

// between 1-100, inclusive - changes how quickly transitions
// between animations occur
void Agent::setInterpolation( int interp )
{
	dbSetObjectInterpolation( this->getID(), interp );
}

void Agent::moveTo(Triple goal)
{
	currPath.clear();
	currPath = pathfinder.navigate( getPosition(), goal );
	traverser.setPath( & currPath, getRotation() );
	setState( Walking );
	changedState = true;
}

void Agent::setWalkSpeed(float newSpeed)
{
	traverser.setWalkSpeed( newSpeed );
}

void Agent::setTurnSpeed( float newSpeed )
{
	traverser.setTurnSpeed( newSpeed );
}

void Agent::update()
{
	oldPose = newPose;

	if (!currPath.empty()) {
		// update new pose
		newPose = traverser.update();
	}

	Object::setPosition( newPose.position );
	PoseableObject::setRotation( newPose.rotation );

	oldState = getState();
	State newState;

	if( currPath.size() == 1 || oldPose == newPose )
	{
		setState( Idle );
	}
	else
	{
		setState( Walking );
	}

	newState = getState();

	if( changedState )
	{
		switch( newState )
		{
		case Idle:
			playAnimation( Animation::Idle );
			break;
		case Walking:
			playAnimation( Animation::Move );
			break;
		default:
			break;
		}

		changedState = false;
	}
}

///////////////////////////////////////////////////////
// return the state of the object
Agent::State
Agent::getState() const
{
	return state;
}

///////////////////////////////////////////////////////
// set the state of the object
void
Agent::setState(State s)
{
	oldState = state;
	state = s;
	changedState = oldState == getState() ? false : true;
}
